#include <malloc.h>
#include <iostream>
#include <string.h>
#include "RPCheader.h"


////////////////////////////////////////////////////////////////////////////////////////////
//
// This server implements the following procedures:
//

int displayParms (int *argTypes, void **args);
int copyChar     (int *argTypes, void **args);


////////////////////////////////////////////////////////////////////////////////////////////
//
// This server procedure simply displays parameters that are sent to it by the client
//

int displayParms (int *argTypes, void **args) {

  std::cerr << "You have entered the server displayParms" << std::endl;

  for (int i = 0; argTypes[i] != 0; ++i) {

    int arrayLength = argTypes[i] & 0xFFFF;

    switch ((argTypes[i] & 0xFF0000) >> 16) {
    case ARG_CHAR :
      std::cerr << "Argument " << i << " is char with value: " << *(char *)args[i] << std::endl;
      if (arrayLength) {
        std::cerr << "Argument is an array of length " << arrayLength << std::endl;
        std::cerr << "Last value of array is " << ((char *)args[i])[arrayLength - 1] << std::endl;
      }
      break;

    case ARG_SHORT :
      std::cerr << "Argument " << i << " is short with value: " << *(short *)args[i] << std::endl;
      if (arrayLength) {
        std::cerr << "Argument is an array of length " << arrayLength << std::endl;
        std::cerr << "Last value of array is " << ((short *)args[i])[arrayLength - 1] << std::endl;
      }
      break;

    case ARG_INT :
      std::cerr << "Argument " << i << " is int with value: " << *(int *)args[i] << std::endl;
      if (arrayLength) {
        std::cerr << "Argument is an array of length " << arrayLength << std::endl;
        std::cerr << "Last value of array is " << ((int *)args[i])[arrayLength - 1] << std::endl;
      }
      break;

    case ARG_LONG :
      std::cerr << "Argument " << i << " is long with value: " << *(long *)args[i] << std::endl;
      if (arrayLength) {
        std::cerr << "Argument is an array of length " << arrayLength << std::endl;
        std::cerr << "Last value of array is " << ((long *)args[i])[arrayLength - 1] << std::endl;
      }
      break;

    case ARG_FLOAT :
      std::cerr << "Argument " << i << " is float with value: " << *(float *)args[i] << std::endl;
      if (arrayLength) {
        std::cerr << "Argument is an array of length " << arrayLength << std::endl;
        std::cerr << "Last value of array is " << ((float *)args[i])[arrayLength - 1] << std::endl;
      }
      break;

    case ARG_DOUBLE :
      std::cerr << "Argument " << i << " is double with value: " << *(double *)args[i] << std::endl;
      if (arrayLength) {
        std::cerr << "Argument is an array of length " << arrayLength << std::endl;
        std::cerr << "Last value of array is " << ((double *)args[i])[arrayLength - 1] << std::endl;
      }
      break;

    case ARG_STRING :
	if (!arrayLength) {
	    std::cerr << "Argument " << i << " is string with value: " << (char *)args[i] << std::endl;
	}
	else {
	    std::cerr << "Argument is an array of length " << arrayLength << std::endl;
	    std::cerr << "First value of array is " << ((char**)args[i])[0] << std::endl;
	    std::cerr << "Last value of array is " << ((char**)args[i])[arrayLength - 1] << std::endl;
	}
      break;

    default :
      std::cerr << "Argument " << i << " is of unknown type" << std::endl;
      break;
    }

  }
  return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////
//
//  Procedure copyChar expects the argument types to be two char's.
//  Failure to do so will result in it returning a -1.
//  It copies the second char to the first char.
//

int copyChar (int *argTypes, void **args) {

	cout << "COPY CHAR!!!" << endl;

  if ((argTypes[0] != (rpcChar | rpcOutput))  ||
      (argTypes[1] != (rpcChar | rpcInput))) {
    return -1;
  }

  *(char *)args[0] = *(char *)args[1];   // dest = src;
  return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////
//
//  Main simply registers the procedures and then enters the
//  stub execute mode.
//

int main ( void ) {

  int argTypes[4];
  int argT[2];
  int result = 0;

  //void **args = (void **)malloc(PARAMETER_COUNT  * sizeof(void *));

  // copyChar(dest, src);

	//extra argType compared to sampleServer1

  argTypes[0] = rpcChar | rpcOutput;       // dest
  argTypes[1] = rpcChar | rpcInput;        // src
  argTypes[2] = rpcChar | rpcOutput;
  argTypes[3] = 0;                         // Terminator

  result = rpcRegister("copyChar", argTypes, &copyChar);

  if (result < 0)
    std::cerr << "rpcRegister generated an error: " << result << std::endl;
  else if (result > 0)
    std::cerr << "rpcRegister generated a warning: " << result << std::endl;


  // displayParms(...)
  argT[0] = 0;

  result = rpcRegister("displayParms", argT, &displayParms);

  if (result < 0)
    std::cerr << "rpcRegister generated an error: " << result << std::endl;
  else if (result > 0)
    std::cerr << "rpcRegister generated a warning: " << result << std::endl;


  // And now hand control over to the the server stub

  result = rpcExecute();

  // Someone terminated the server stub.  Let's print the result and exit

  std::cerr << "Server was terminated with result: " << result << std::endl;

  return result;
}
